//
//  ExamPilstEqual.m
//  ocdemo
//
//  Created by JIENING ZHANG on 2020/5/10.
//  Copyright © 2020 JIENING ZHANG. All rights reserved.
//

#import "ExamPilstEqual.h"

@implementation ExamPilstEqual


// lObj rObj 是 plist 类型对象
// (instances of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary)
+ (BOOL)testPlistObjEqual:(id)lObj with:(id)rObj containerArr:(NSMutableArray *)containerArr {
    // 同一个对象，直接返回 Yes
    if(lObj == rObj) {
        NSLog(@"same address, lObj == rObj");
        return YES;
    }
    
    // 字符串
    if([lObj isKindOfClass:[NSString class]]) {
        if(! [rObj isKindOfClass:[NSString class]]) {
            return NO;
        }
        NSLog(@"字符串 : %@ %@", ((NSString *)lObj), ((NSString *)rObj));
        return  [((NSString *)lObj) isEqualToString:(NSString *)rObj];
    }
    
    // 数值
    if([lObj isKindOfClass:[NSNumber class]]) {
        if(! [rObj isKindOfClass:[NSNumber class]]) {
            return NO;
        }
        NSLog(@"数值 : %@ %@", ((NSNumber *)lObj), ((NSNumber *)rObj));
        return  [((NSNumber *)lObj) isEqualToNumber:(NSNumber *)rObj];
    }
    
    // data
    if([lObj isKindOfClass:[NSData class]]) {
        if(! [rObj isKindOfClass:[NSData class]]) {
            return NO;
        }
        NSLog(@"data : %@ %@", ((NSData *)lObj), ((NSData *)rObj));
        return  [((NSData *)lObj) isEqualToData:(NSData *)rObj];
    }
    
    // 日期
    if([lObj isKindOfClass:[NSDate class]]) {
        if(! [rObj isKindOfClass:[NSDate class]]) {
            return NO;
        }
        NSLog(@"日期 : %@ %@", ((NSDate *)lObj), ((NSDate *)rObj));
        return  [((NSDate *)lObj) isEqualToDate:(NSDate *)rObj];
    }
    
    // 字典
    if([lObj isKindOfClass:[NSDictionary class]]) {
        if(! [rObj isKindOfClass:[NSDictionary class]]) {
            return NO;
        }
        
        //*
        // 防止递归 死循环
        for(NSArray *comparePair in containerArr) {
            id pairObj1 = comparePair[0];
            id pairObj2 = comparePair[1];
            if( (lObj == pairObj1 || lObj==pairObj2) &&
                (rObj == pairObj1 || rObj==pairObj2) ) {
                // 要比较的 容器对象 已经在递归栈上了
                NSLog(@"字典 : 要比较的 容器对象 已经在递归栈上了 %lld %lld", (long long)lObj, (long long)rObj);
                return YES;
            }
        }
        [containerArr addObject:@[lObj, rObj]];
        //*/
        
        return [ExamPilstEqual testDicEqual:(NSDictionary *)lObj with:(NSDictionary *)rObj containerArr:containerArr];
    }
    
    // 数组
    if([lObj isKindOfClass:[NSArray class]]) {
        if(! [rObj isKindOfClass:[NSArray class]]) {
            return NO;
        }
        
        //*
        // 防止递归 死循环
        for(NSArray *comparePair in containerArr) {
            id pairObj1 = comparePair[0];
            id pairObj2 = comparePair[1];
            if( (lObj == pairObj1 || lObj==pairObj2) &&
                (rObj == pairObj1 || rObj==pairObj2) ) {
                // 要比较的 容器对象 已经在递归栈上了
                NSLog(@"数组 : 要比较的 容器对象 已经在递归栈上了 %lld %lld", (long long)lObj, (long long)rObj);
                return YES;
            }
        }
        [containerArr addObject:@[lObj, rObj]];
        //*/
        
        return [ExamPilstEqual testArrayEqual:(NSArray *)lObj with:(NSArray *)rObj containerArr:containerArr];
    }
    
    NSLog(@"不是 plist 类型");
    
    return NO;
}


+ (BOOL)testArrayEqual:(NSArray *)lArr with:(NSArray *)rArr {
    NSMutableArray *containerArr = [NSMutableArray array];
    [containerArr addObject:@[(lArr ?: @""), (rArr ?: @"")]];
    
    return [ExamPilstEqual testArrayEqual:lArr with:rArr containerArr:containerArr];
}

+ (BOOL)testArrayEqual:(NSArray *)lArr with:(NSArray *)rArr containerArr:(NSMutableArray *)containerArr {
    
    // 同一个对象，直接返回 Yes
    if(lArr == rArr) {
        return YES;
    }
    
    if([lArr count] != [rArr count]) {
        return NO;
    }
    
    for(int index=0; index< [lArr count]; ++index) {
        
        NSLog(@"index %d", index);
        
        if(! [ExamPilstEqual testPlistObjEqual:lArr[index] with:rArr[index] containerArr:containerArr]) {
            return NO;
        }
    }
    
    return YES;
}


+ (BOOL)testDicEqual:(NSDictionary *)lDic with:(NSDictionary *)rDic {
    NSMutableArray *containerArr = [NSMutableArray array];
    [containerArr addObject:@[(lDic ?: @""), (rDic ?: @"")]];
    
    return [ExamPilstEqual testDicEqual:lDic with:rDic containerArr:containerArr];
}

// lDic rDic 的value 都是 plist 类型对象
// (instances of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary)
+ (BOOL)testDicEqual:(NSDictionary *)lDic with:(NSDictionary *)rDic containerArr:(NSMutableArray *)containerArr {
    
    // 同一个对象，直接返回 Yes
    if(lDic == rDic) {
        return YES;
    }
    
    if([[lDic allKeys] count] != [[rDic allKeys] count]) {
        return NO;
    }
    
    for(NSString *key in lDic) {
        
        NSLog(@"key %@", key);
        
        if(! [ExamPilstEqual testPlistObjEqual:lDic[key] with:rDic[key] containerArr:containerArr]) {
            return NO;
        }
    }
    
    return YES;
}

+ (void)demoLogic {
    NSDictionary *dDic1 = @{
                               @"January" :     @(31),
                               @"February" :    @(28),
                               @"March" :       @(31),
                               @"April" :       @(30),
                               @"May" :         @(31),
                               @"June" :        @(30),
                               @"July" :        @(31),
                               @"August" :      @(31),
                               @"September" :   @(30),
                               @"October" :     @(31),
                               @"November" :    @(30),
                               @"December" :    @(31),
                               };

    NSDictionary *dDic2 = @{
                               @"January" :     @(31),
                               @"February" :    @(28),
                               @"March" :       @(31),
                               @"April" :       @(30),
                               @"May" :         @(31),
                               @"June" :        @(30),
                               @"July" :        @(31),
                               @"August" :      @(31),
                               @"September" :   @(30),
                               @"October" :     @(31),
                               @"November" :    @(30),
                               @"December" :    @(31),
                               };
    
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    df.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    
    NSString *dateStr1 = @"2019-05-05 23:32:59";
    NSString *dateStr2 = [@"2019-05-04 23:32:59" stringByReplacingOccurrencesOfString:@"-04" withString:@"-05"];
    NSDate *date1 = [df dateFromString:dateStr1];
    //NSDate *date2 = [[df dateFromString:@"2019-05-04 23:32:59"] dateByAddingTimeInterval:86400];
    NSDate *date2 = [df dateFromString:@"2019-05-04 23:32:59"];
    NSData *data1 = [dateStr1 dataUsingEncoding:NSUTF8StringEncoding];
    NSData *data2 = [dateStr2 dataUsingEncoding:NSUTF8StringEncoding];
    
    NSMutableDictionary *multyDic1 = [NSMutableDictionary dictionary];
    NSMutableDictionary *multyDic2 = [NSMutableDictionary dictionary];
    NSMutableArray *mArr1 = [NSMutableArray array];
    NSMutableArray *mArr2 = [NSMutableArray array];
    
    multyDic1[@"arr"] = mArr1;
    multyDic1[@"dic"] = dDic1;
    
    multyDic2[@"arr"] = mArr2;
    multyDic2[@"dic"] = dDic2;
    
    mArr1[0] = dDic1;
    mArr1[1] = @{@"mdic": multyDic1, @"tmp":@(1), @"kk":@(0)};
    
    mArr2[0] = dDic2;
    mArr2[1] = @{@"mdic": multyDic2, @"tmp":@(YES), @"kk":@(NO)};
    
    NSDictionary *lDic = @{@"字符":dateStr1,
                            @"日期":date1,
                            @"data":data1,
                            @"字典单层":dDic1,
                            @"数组单层":[dDic1 allKeys],
                            @"字典多层":multyDic1,
                            @"数组多层":mArr1,
    };
    
    NSDictionary *rDic = @{@"字符":dateStr2,
                           @"日期":date2,
                           @"data":data2,
                           @"字典单层":dDic2,
                           @"数组单层":[dDic2 allKeys],
                           @"字典多层":multyDic2,
                           @"数组多层":mArr2,
    };

    if([ExamPilstEqual testDicEqual:lDic with:rDic]) {
        NSLog(@"lDic == rDic");
    } else {
        NSLog(@"lDic != rDic");
    }
}

@end
